package com.sneakxy.cloudbase.platform.service;

import java.io.Serializable;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import com.sneakxy.cloudbase.platform.bean.TimeEntity;
import com.sneakxy.cloudbase.platform.repository.BaseRepository;
import com.sneakxy.mybatis.commons.repository.query.domain.Criteria;

/**
 * @author 潜行的青衣
 * @see
 */
public abstract class BaseService<T, I extends Serializable, R extends BaseRepository<T, I>> implements IBaseService<T, I> {
	
	@Autowired
	private R repository;
	
	@Override
	public String getTableName(String id, int size) {
		return getTableName(Math.abs(new HashCodeBuilder().append(id).toHashCode()), size);
	}

	@Override
	public String getTableName(long id, int size) {
		long index = id % size;
		return StringUtils.join(this.getRepository().getTableName(), "_", index);
	}

	@Override
	public String getTableName(int id, int size) {
		int index = id % size;
		return StringUtils.join(this.getRepository().getTableName(), "_", index);
	}

	public Iterable<T> findAll() {
		return this.getRepository().findAll();
	}

	@Override
	public Iterable<T> findAll(String tableName) {
		return this.getRepository().findAll(tableName);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#findAll(org.springframework.data.domain.Sort)
	 */
	@Override
	public Iterable<T> findAll(Sort sort) {
		return this.getRepository().findAll(sort);
	}

	@Override
	public Iterable<T> findAll(String tableName, Sort sort) {
		return getRepository().findAll(tableName, sort);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#findAll(java.lang.Iterable)
	 */
	@Override
	public Iterable<T> findAll(Iterable<I> ids) {
		return this.getRepository().findAllById(ids);
	}
	
	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#findAll(org.springframework.data.domain.Pageable)
	 */
	@Override
	public Page<T> findAll(Pageable pageable) {
		return this.getRepository().findAll(pageable);
	}
	
	@Override
	public Page<T> findAll(String tableName, Pageable pageable) {
		return getRepository().findAll(tableName, pageable);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#findOne(java.io.Serializable)
	 */
	@Override
	public T findOne(I id) {
		Optional<T> result = this.getRepository().findById(id);
		return result.isPresent() ? result.get() : null;
	}

	@Override
	public T findOne(I id, String tableName) {
		Optional<T> result = this.getRepository().findById(id, tableName);
		return result.isPresent() ? result.get() : null;
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#exists(java.io.Serializable)
	 */
	@Override
	public boolean exists(I id) {
		return this.getRepository().existsById(id);
	}

	@Override
	public boolean exists(I id, String tableName) {
		return this.getRepository().existsById(id, tableName);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#findOne(com.sneakxy.mybatis.commons.repository.query.domain.Criteria)
	 */
	@Override
	public T findOne(Criteria<T> criteria) {
		return this.getRepository().findOne(criteria);
	}

	@Override
	public T findOne(Criteria<T> criteria, String tableName) {
		return this.getRepository().findOne(criteria, tableName);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#findAll(com.sneakxy.mybatis.commons.repository.query.domain.Criteria)
	 */
	@Override
	public List<T> findAll(Criteria<T> criteria) {
		return this.getRepository().findAll(criteria);
	}

	@Override
	public List<T> findAll(Criteria<T> criteria, String tableName) {
		return this.getRepository().findAll(criteria, tableName);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#findAll(com.sneakxy.mybatis.commons.repository.query.domain.Criteria, org.springframework.data.domain.Pageable)
	 */
	@Override
	public Page<T> findAll(Criteria<T> criteria, Pageable pageable) {
		return this.getRepository().findAll(criteria, pageable);
	}

	@Override
	public Page<T> findAll(Criteria<T> criteria, String tableName, Pageable pageable) {
		return this.getRepository().findAll(criteria, tableName, pageable);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#findAll(com.sneakxy.mybatis.commons.repository.query.domain.Criteria, org.springframework.data.domain.Sort)
	 */
	@Override
	public List<T> findAll(Criteria<T> criteria, Sort sort) {
		return this.getRepository().findAll(criteria, sort);
	}

	@Override
	public List<T> findAll(Criteria<T> criteria, String tableName, Sort sort) {
		return this.getRepository().findAll(criteria, tableName, sort);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#save(java.lang.Object)
	 */
	@Override
	public <S extends T> S save(S entity) {
		if(entity instanceof TimeEntity) {
			TimeEntity timeEntity = (TimeEntity) entity;
			String time = DateFormatUtils.format(Calendar.getInstance(), DATE_TIME_FORMATTER);
			if(StringUtils.isBlank(timeEntity.getCreatetime()) && getRepository().isNew(entity)) {
				timeEntity.setCreatetime(time);
			}
			timeEntity.setUpdatetime(time);
		}
		return this.getRepository().save(entity);
	}

	@Override
	public <S extends T> S save(S entity, String tableName) {
		if(entity instanceof TimeEntity) {
			TimeEntity timeEntity = (TimeEntity) entity;
			String time = DateFormatUtils.format(Calendar.getInstance(), DATE_TIME_FORMATTER);
			if(StringUtils.isBlank(timeEntity.getCreatetime()) && getRepository().isNew(entity)) {
				timeEntity.setCreatetime(time);
			}
			timeEntity.setUpdatetime(time);
		}
		return this.getRepository().save(entity, tableName);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#save(java.lang.Iterable)
	 */
	@Override
	public <S extends T> Iterable<S> save(Iterable<S> entities) {
		String time = DateFormatUtils.format(Calendar.getInstance(), DATE_TIME_FORMATTER);
		Iterator<S> it = entities.iterator();
		S entity = null;
		TimeEntity timeEntity = null;
		while(it.hasNext()) {
			entity = it.next();
			if(entity instanceof TimeEntity) {
				timeEntity = (TimeEntity) entity;
				if(StringUtils.isBlank(timeEntity.getCreatetime()) && getRepository().isNew(entity)) {
					timeEntity.setCreatetime(time);
				}
				timeEntity.setUpdatetime(time);
			}
		}
		return this.getRepository().saveAll(entities);
	}
	
	@Override
	public <S extends T> S update(S entity, Criteria<S> criteria, String tableName) {
		getRepository().update(entity, tableName, criteria);
		return entity;
	}

	@Override
	public <S extends T> S update(S entity, Criteria<S> criteria) {
		getRepository().update(entity, criteria);
		return entity;
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#delete(java.io.Serializable)
	 */
	@Override
	public void delete(I id) {
		this.getRepository().deleteById(id);
	}

	@Override
	public void delete(I id, String tableName) {
		this.getRepository().deleteById(id, tableName);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#delete(java.lang.Object)
	 */
	@Override
	public void delete(T entity) {
		this.getRepository().delete(entity);
	}

	@Override
	public void delete(Criteria<T> criteria, String tableName) {
		getRepository().delete(criteria, tableName);
	}

	@Override
	public void delete(Criteria<T> criteria) {
		getRepository().delete(criteria);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#delete(java.lang.Iterable)
	 */
	@Override
	public void delete(Iterable<? extends T> entities) {
		this.getRepository().deleteAll(entities);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#deleteAll()
	 */
	@Override
	public void deleteAll() {
		this.getRepository().deleteAll();
	}

	@Override
	public void deleteAll(String tableName) {
		this.getRepository().deleteAll(tableName);
	}

	public long count(Criteria<T> criteria) {
		return this.getRepository().count(criteria);
	}

	@Override
	public long count(Criteria<T> criteria, String tableName) {
		return this.getRepository().count(criteria, tableName);
	}

	/* (non-Javadoc)
	 * @see com.nsxy.common.service.IBaseService#count()
	 */
	@Override
	public long count() {
		return this.getRepository().count();
	}
	
	@Override
	public long count(String tableName) {
		return this.getRepository().count(tableName);
	}

	public R getRepository() {
		return this.repository;
	}

}
